package com.project.base.common;

import com.project.base.core.tables.RequestTimeDetail;
import com.project.base.entity.*;
import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


public class LogParseUtils {

    public static DubboLogInfo parseDubboLog(String logContent) {
        DubboLogInfo dubboLogInfo = new DubboLogInfo();
        if (!LogProcessorUtil.isDubboMethodEndLogContent(logContent) && !LogProcessorUtil.isDubboMethodStartLogContent(logContent)) {
            return dubboLogInfo;
        }
        logContent = logContent.replaceAll(",", "");
        String[] logs = logContent.split("\\s+");
        if (logs.length < 9) {
            return dubboLogInfo;
        }
        dubboLogInfo.set_interface(logs[3]);
        dubboLogInfo.set_method(logs[6]);
        dubboLogInfo.setFlag(logs[8]);

        return dubboLogInfo;
    }

    /**
     * 将一整行日志解析成一个日志对象
     *
     * @param log
     * @return
     */
    public static LogInfo parseLog(String log) {
        String[] logs = log.split("\\s+");
        LogInfo logInfo = new LogInfo();
        if (logs.length < 6) {
            return null;
        }
        String dateStr = logs[0] + " " + logs[1];
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss,S");
        try {
            logInfo.setPrintTime(format.parse(dateStr));
        } catch (ParseException e) {
            return null;
        }
        String levelAppName = logs[2];
        levelAppName = levelAppName.replace("[LvLogS]", ",");
        String[] levelAppNames = levelAppName.split(",");
        logInfo.setLogLevel(levelAppNames[0]);
        logInfo.setAppName(levelAppNames[1]);
        String threadName = logs[3];
        int indexOf = threadName.indexOf("]");
        if (indexOf == -1) {
            return null;
        }
        threadName = threadName.substring(1, indexOf);
        logInfo.setThreadName(threadName);
        String classNameInfo = logs[4];
        indexOf = classNameInfo.indexOf(")");
        if (indexOf == -1) {
            return null;
        }
        classNameInfo = classNameInfo.substring(1, indexOf);
        if (!classNameInfo.matches("\\w+.\\w+:\\d+")) {
            return null;
        }
        String[] classNameInfos = classNameInfo.split(":");
        logInfo.setClassName(classNameInfos[0]);
        logInfo.setClassLineNum(classNameInfos[1]);
        String[] logStrs = log.split(logs[4]);
        if (logStrs.length < 2) {
            return null;
        }
        String content = logStrs[1];
        indexOf = content.indexOf("-");
        if (indexOf == -1) {
            return null;
        }
        content = content.substring(indexOf + 2);
        logInfo.setContent(content);
        return logInfo;
    }

    public static BaseLog parseClientServiceCommonParam(String log) {
        if (StringUtils.isBlank(log)) {
            return null;
        }
        String[] commonParams = log.split(Constants.SEPERATOR);
        if (commonParams.length < 20) {
            return null;
        }

        BaseLog baseLog = new BaseLog();
        baseLog.logType = commonParams[0];
        baseLog.timeStamp = commonParams[1];
        DeviceInfoLog deviceInfoLog = new DeviceInfoLog();
        deviceInfoLog.firstChannel = commonParams[2];
        deviceInfoLog.secondChannel = commonParams[3];
        deviceInfoLog.udid = commonParams[4];
        deviceInfoLog.osVersion = commonParams[5];
        deviceInfoLog.userAgent = commonParams[6];
        baseLog.deviceInfo = deviceInfoLog;
        UserInfoLog userInfoLog = new UserInfoLog();
        userInfoLog.userId = commonParams[7];
        userInfoLog.ip = commonParams[8];
        userInfoLog.lvversion = commonParams[9];
        userInfoLog.longitude = commonParams[10];
        userInfoLog.latitude = commonParams[11];
        userInfoLog.lvsessionid = commonParams[12];
        userInfoLog.adChannel = commonParams[13];
        baseLog.userInfo = userInfoLog;
        AccessLog accessLog = new AccessLog();
        accessLog.method = commonParams[14];
        accessLog.version = commonParams[15];
        accessLog.pageCode = commonParams[16];
        accessLog.lastPageCode = commonParams[17];
        accessLog.productType = commonParams[18];
        accessLog.clientTimestamp = commonParams[19];
        baseLog.accessLog = accessLog;

        return baseLog;
    }

    public static List<String> parseClientServiceSpecialParam(String logCotent) {
        if (StringUtils.isBlank(logCotent)) {
            return null;
        }
        String[] commonParams = logCotent.split(Constants.SEPERATOR);
        if (commonParams.length < 1) {
            return null;
        }
        return Arrays.asList(commonParams);
    }

    public static List<RequestTimeDetail> parseApiRequestTimeDetail(List<String> logList) {
        List<RequestTimeDetail> apiRequestTimeDetailList = new ArrayList<RequestTimeDetail>();
        if (logList == null || logList.isEmpty()) {
            return apiRequestTimeDetailList;
        }
        Collections.sort(logList, new LogComparator());
        LogInfo startLogInfo = LogParseUtils.parseLog(logList.get(0));
        long startTime = startLogInfo.getPrintTime().getTime();
        LogInfo endLogInfo = LogParseUtils.parseLog(logList.get(logList.size() - 1));
        long endTime = endLogInfo.getPrintTime().getTime();
        RequestTimeDetail total = new RequestTimeDetail();
        total.setThreadName(startLogInfo.getThreadName());
        total.setTimeType(LogEnums.REQUEST_TIME_TYPE.ALL.name());
        total.setRequestTime(startTime);
        total.setResponseTime(endTime);
        total.setMillisecond(endTime - startTime);
        // 所有dubbo的性能日志解析结果
        List<LogInfo> logInfoList = new ArrayList<LogInfo>();
        for (String log : logList) {
            LogInfo logInfo = LogParseUtils.parseLog(log);
            if (logInfo == null) {
                continue;
            }
            if (Constants.COMMON_PARAM_DATA.equals(logInfo.getClassName())) {
                String content = logInfo.getContent();
                BaseLog baseLog = LogParseUtils.parseClientServiceCommonParam(content);
                total.setRequestName(baseLog.accessLog.method);
                total.setRequestVersion(baseLog.accessLog.version);
            }
            if (Constants.DUBBO_PARAM_DATA.equals(logInfo.getClassName()) && (LogProcessorUtil.isDubboMethodStartLogContent(logInfo.getContent()) || LogProcessorUtil.isDubboMethodEndLogContent(logInfo.getContent()))) {
                DubboLogInfo dubboLogInfo = parseDubboLog(logInfo.getContent());
                logInfo.setDubboLog(dubboLogInfo);
                logInfoList.add(logInfo);
            }
        }
        apiRequestTimeDetailList.add(total);

        RequestTimeDetail tempApiRequestTimeDetail = new RequestTimeDetail();
        for (int i = 0; i < logInfoList.size(); i++) {
            LogInfo logInfo = logInfoList.get(i);
            if ("start".equals(logInfo.getDubboLog().getFlag())) {
                tempApiRequestTimeDetail.setRequestTime(logInfo.getPrintTime().getTime());
                tempApiRequestTimeDetail.setRequestName(logInfo.getDubboLog().get_interface());
                tempApiRequestTimeDetail.setRequestVersion(logInfo.getDubboLog().get_method());
                tempApiRequestTimeDetail.setThreadName(logInfo.getThreadName());
                tempApiRequestTimeDetail.setTimeType(LogEnums.REQUEST_TIME_TYPE.DUBBO.name());
            }
            if ("end".equals(logInfo.getDubboLog().getFlag())) {
                if (StringUtils.isNotBlank(tempApiRequestTimeDetail.getRequestName()) && StringUtils.isNotBlank(tempApiRequestTimeDetail.getRequestVersion())) {
                    if (tempApiRequestTimeDetail.getRequestName().equals(logInfo.getDubboLog().get_interface()) && tempApiRequestTimeDetail.getRequestVersion().equals(logInfo.getDubboLog().get_method())) {
                        tempApiRequestTimeDetail.setResponseTime(logInfo.getPrintTime().getTime());
                        tempApiRequestTimeDetail.setMillisecond(logInfo.getPrintTime().getTime() - tempApiRequestTimeDetail.getRequestTime());
                        apiRequestTimeDetailList.add(tempApiRequestTimeDetail);
                        tempApiRequestTimeDetail = new RequestTimeDetail();
                    }
                }
            }
        }
        return apiRequestTimeDetailList;
    }


    public static void main(String[] args) {
//		parseDubboLog("interface = interface com.lvmama.comm.tnt.service.TntSellPackageService, method = getSellPackageListByChannel -- start");
//		parseLog("2016-07-16 02:31:49,502 ERROR[LvLogS]client-service [FLUME-f4130278-6931-41b3-8638-e5bd70f9ce94] (ApiMethodIntercept.java:173) - ");
    }
}
